home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-2.iso / os2 / gnucal.zip / gcal_rc.c < prev    next >
C/C++ Source or Header  |  1995-12-18  |  56KB  |  1,876 lines

  1. /*
  2. *  gcal_rc.c:  Pool of special functions necessary for managing the fixed dates
  3. *
  4. *
  5. *  Copyright (C) 1994, 1995 Thomas Esken
  6. *
  7. *  This software doesn't claim completeness, correctness or usability.
  8. *  On principle I will not be liable for any damages or losses (implicit
  9. *  or explicit), which result from using or handling my software.
  10. *  If you use this software, you agree without any exception to this
  11. *  agreement, which binds you LEGALLY !!
  12. *
  13. *  This program is free software; you can redistribute it and/or modify
  14. *  it under the terms of the `GNU General Public License' as published by
  15. *  the `Free Software Foundation'; either version 2, or (at your option)
  16. *  any later version.
  17. *
  18. *  You should have received a copy of the `GNU General Public License'
  19. *  along with this program; if not, write to the:
  20. *    Free Software Foundation
  21. *    59 Temple Place, Suite 330
  22. *    Boston, MA 02111-1307  USA
  23. */
  24.  
  25.  
  26.  
  27. /*
  28. *  Include definition header file to see whether USE_RC is defined there.
  29. *    compile this module only if USE_RC is defined, otherwise skip it.
  30. */
  31. #include "gcal_tai.h"
  32.  
  33.  
  34.  
  35. #if USE_RC
  36. #  ifdef RCSID
  37. static char rcsid[]="$Id: gcal_rc.c 0.39 1995/12/18 00:03:09 tom Exp $";
  38. #  endif
  39.  
  40.  
  41.  
  42. /*
  43. *  Include header files
  44. */
  45. #  if HAVE_CTYPE_H
  46. #    include <ctype.h>
  47. #  endif
  48. #  include "gcal.h"
  49.  
  50.  
  51.  
  52. /*
  53. *  Function prototypes
  54. */
  55. #  if __cplusplus
  56. extern "C"
  57. {
  58. #  endif
  59. /*
  60. ************************************************** Defined in `gcal_hdy.c'
  61. */
  62. IMPORT int
  63. eval_holiday __P_((      int  day,
  64.                    const int  month,
  65.                    const int  year,
  66.                    const int  wd,
  67.                    const Bool forwards));
  68. /*
  69. ************************************************** Defined in `gcal_tty.c'
  70. */
  71. IMPORT void
  72. print_text __P_((      FILE       *fp,
  73.                        char       *txt_line,
  74.                  const Dmode_enum  mode));
  75. /*
  76. ************************************************** Defined in `gcal_utl.c'
  77. */
  78. IMPORT void
  79. my_error __P_((const int   exit_status,
  80.                const char *module_name,
  81.                const int   module_line,
  82.                const char *var_name,
  83.                const int   var_contents));
  84. IMPORT int
  85. my_atoi __P_((const char *s));
  86. IMPORT int
  87. compare_d_m_name __P_((const char       *s,
  88.                        const Cmode_enum  mode));
  89. IMPORT Ulint
  90. date2num __P_((const int day,
  91.                const int month,
  92.                const int year));
  93. IMPORT Bool
  94. jdate2sdate __P_((      int  jdate,
  95.                   const int  is_leap_year,
  96.                         int *day,
  97.                         int *month));
  98. IMPORT int
  99. weekday_of_date __P_((const int day,
  100.                       const int month,
  101.                       const int year));
  102. IMPORT int
  103. day_of_year __P_((const int day,
  104.                   const int month,
  105.                   const int year));
  106. IMPORT int
  107. days_of_february __P_((const int year));
  108. IMPORT Bool
  109. valid_date __P_((const int day,
  110.                  const int month,
  111.                  const int year));
  112. IMPORT int
  113. weekno2jday __P_((      int week,
  114.                   const int year));
  115. IMPORT int
  116. knuth_easter_formula __P_((const int year));
  117. /*
  118. ************************************************** Defined in `gcal_rc.c'
  119. */
  120. EXPORT void
  121. rc_clean_flags __P_((void));
  122. EXPORT char *
  123. rc_get_date __P_((      char *ptr_char,
  124.                         Bool *is_weekday_mode,
  125.                         int  *d,
  126.                         int  *m,
  127.                         int  *y,
  128.                         int  *n,
  129.                         int  *len,
  130.                         char *hc,
  131.                         int  *hn,
  132.                         int  *hwd,
  133.                   const char *filename,
  134.                   const int   line,
  135.                   const char *line_buffer,
  136.                   const Bool  on_error_exit));
  137. EXPORT Bool
  138. precomp_nth_wd __P_((      int         diff,
  139.                      const int         wd,
  140.                            int        *n,
  141.                            int        *day,
  142.                            int        *month,
  143.                            int        *year,
  144.                      const Cmode_enum  mode));
  145. EXPORT Bool
  146. precomp_date __P_((      int         diff,
  147.                    const int         wd,
  148.                          int        *day,
  149.                          int        *month,
  150.                    const int         year,
  151.                    const Cmode_enum  mode));
  152. EXPORT Bool
  153. set_dvar __P_((const char      *line_buffer,
  154.                const char      *filename,
  155.                const int        line,
  156.                const Dvar_enum  mode));
  157. EXPORT void
  158. nth_weekday_of_month __P_((      int  *d,
  159.                                  int  *m,
  160.                                  int  *y,
  161.                            const int  *n,
  162.                                  Bool *is_weekday_mode));
  163. EXPORT void
  164. prev_date __P_((int *day,
  165.                 int *month,
  166.                 int *year));
  167. EXPORT void
  168. next_date __P_((int *day,
  169.                 int *month,
  170.                 int *year));
  171. EXPORT void
  172. num2date __P_((Ulint  julian_days,
  173.                int   *day,
  174.                int   *month,
  175.                int   *year));
  176. EXPORT Slint
  177. d_between __P_((const int d1,
  178.                 const int m1,
  179.                 const int y1,
  180.                 const int d2,
  181.                 const int m2,
  182.                 const int y2));
  183. EXPORT Slint
  184. w_between __P_((const int d1,
  185.                 const int m1,
  186.                 const int y1,
  187.                 const int d2,
  188.                 const int m2,
  189.                 const int y2));
  190. EXPORT Slint
  191. m_between __P_((const int m1,
  192.                 const int y1,
  193.                 const int m2,
  194.                 const int y2));
  195. LOCAL void
  196. dvar_warning __P_((const int   exit_status,
  197.                    const char  dvar,
  198.                    const char *filename,
  199.                    const int   line,
  200.                    const char *text));
  201. #  if __cplusplus
  202. }
  203. #  endif
  204.  
  205.  
  206.  
  207. /*
  208. *  Declare public(extern) variables
  209. */
  210. IMPORT const int    dvec[MONTH_MAX];          /* Amount of days in months' */
  211. IMPORT const int    mvec[MONTH_MAX];          /* Number of past days of month */
  212. IMPORT Dvar_struct  rc_dvar[RC_DVAR_MAX];     /* Date variables a[=`mmdd']...z[] (`yyyy'@{a|b|...|z}[[-]<n>]) */
  213. IMPORT int          len_year_max;             /* String length of the maximum year able to compute */
  214. IMPORT int          warning_level;            /* --debug[=0...WARN_LVL_MAX] */
  215. IMPORT int          start_day;                /* -s<0,1...7|day name> */
  216. IMPORT int          day;                      /* Current day */
  217. IMPORT int          month;                    /* Current month */
  218. IMPORT int          year;                     /* Current year */
  219. IMPORT int          fiscal_month;             /* Starting month of a fiscal year */
  220. IMPORT int          is_leap_year;             /* Is current year a leap year? */
  221. IMPORT Bool         rc_period_flag;           /* [-c]<<<<n>>[<d|w|+|-]>|`mmdd'|`mmww[w]'<n>> */
  222. IMPORT Bool         rc_period_list;           /* [-c]l */
  223. IMPORT Bool         rc_tomorrow_flag;         /* [-c]t */
  224. IMPORT Bool         rc_week_flag;             /* [-c]w */
  225. IMPORT Bool         rc_month_flag;            /* [-c]m */
  226. IMPORT Bool         rc_year_flag;             /* [-c]y */
  227. IMPORT Bool         rc_week_year_flag;        /* [-c<<n>>]w */
  228. IMPORT Bool         rc_forwards_flag;         /* [-c<<n>|w|m|y>]+ */
  229. IMPORT Bool         rc_backwards_flag;        /* [-c<<n>|w|m|y>]- */
  230. IMPORT Bool         is_3month_mode;           /* Argument is `.' or `.+' or `.-' */
  231. IMPORT Bool         is_3month_mode2;          /* Argument is `..' -> current quarter of actual year */
  232. IMPORT Bool         adate_set;                /* [-c]<n>w and actual date modified */
  233.  
  234.  
  235.  
  236. /*
  237.    Define local(static) variables
  238. */
  239. LOCAL char  str[MAXLEN+1];   /* General purpose text buffer */
  240.  
  241.  
  242.  
  243. #  ifdef ANSI_PROTO
  244. PUBLIC void
  245. rc_clean_flags (void)
  246. #  else /* !ANSI_PROTO */
  247.    PUBLIC void
  248. rc_clean_flags ()
  249. #  endif /* !ANSI_PROTO */
  250. /*
  251.    Clean all global flags (except `rc_period_list'),
  252.      which are related to the fixed date warning period
  253. */
  254. {
  255.    rc_tomorrow_flag=rc_week_flag=rc_month_flag=rc_year_flag
  256.    =rc_week_year_flag=rc_forwards_flag=rc_backwards_flag=rc_period_flag = FALSE;
  257. }
  258.  
  259.  
  260.  
  261. #  ifdef ANSI_PROTO
  262. PUBLIC char *
  263. rc_get_date (      char *ptr_char,
  264.                    Bool *is_weekday_mode,
  265.                    int  *d,
  266.                    int  *m,
  267.                    int  *y,
  268.                    int  *n,
  269.                    int  *len,
  270.                    char *hc,
  271.                    int  *hn,
  272.                    int  *hwd,
  273.              const char *filename,
  274.              const int   line,
  275.              const char *line_buffer,
  276.              const Bool  on_error_exit)
  277. #  else /* !ANSI_PROTO */
  278.    PUBLIC char *
  279. rc_get_date (ptr_char, is_weekday_mode, d, m, y, n, len, hc, hn, hwd,
  280.              filename, line, line_buffer, on_error_exit)
  281.          char *ptr_char;
  282.          Bool *is_weekday_mode;
  283.          int  *d;
  284.          int  *m;
  285.          int  *y;
  286.          int  *n;
  287.          int  *len;
  288.          char *hc;
  289.          int  *hn;
  290.          int  *hwd;
  291.    const char *filename;
  292.    const int   line;
  293.    const char *line_buffer;
  294.    const Bool  on_error_exit;
  295. #  endif /* !ANSI_PROTO */
  296. /*
  297.    Converts the textual/string `date' of a RC-file line to a numerical date
  298.      and returns a pointer to `text'-part of RC-file line(warning message)
  299.      or if a @... or *... day is encoded in date part and year is set to 0000
  300.      in line, then function returns holiday_mode_char(date variable) or
  301.      upper case characters 'D' or 'W' in &hc, day displacement in &hn and a
  302.      possible weekday name(mo...su) converted to a number (1...7) in &hwd for
  303.      further managing of such a line. if any invalid date is given in line,
  304.      then function either returns -1 in &y or leaves program with error_message
  305.      (depending on mode of operation resp., contents of `on_error_exit' variable).
  306. */
  307. {
  308.    register int    i;
  309.    auto     char   str8[8];   /* For date parts, lenght of 7 chars+'\0' maximum! */
  310.    auto     Bool   is_hdy_mode=FALSE;
  311.  
  312.  
  313.    *hc = '\0';
  314.    (*len)=(*hn)=(*hwd)=(*n)=i = 0;
  315.    /*
  316.       Get year
  317.    */
  318.    while (   *ptr_char
  319.           && !MY_ISSPACE(*ptr_char)
  320.           && isdigit(*ptr_char)
  321.           && (i < len_year_max))
  322.      str8[i++] = *ptr_char++;
  323.    str8[i] = '\0';
  324.    *y = my_atoi (str8);
  325.    *len = i;
  326.    /*
  327.       Get month
  328.    */
  329.    i = 0;
  330.    while (   *ptr_char
  331.           && !MY_ISSPACE(*ptr_char)
  332.           && (i < 2))
  333.      str8[i++] = *ptr_char++;
  334.    if (i)
  335.      if (   (   isupper(str8[i-1])
  336.              || islower(str8[i-1]))
  337.          && (   isupper(*ptr_char)
  338.              || islower(*ptr_char)))
  339.        str8[i++] = *ptr_char++;
  340.    str8[i] = '\0';
  341.    *m = my_atoi (str8);
  342.    if (!*m)
  343.      /*
  344.         Check for short (2...3 character) textual month name.
  345.           does not work for month July in case a textual two character lenght
  346.           month name is given, because `ju' is always set to month June.
  347.      */
  348.      *m = compare_d_m_name (str8, MOnth);
  349.    else
  350.      /*
  351.         Error, invalid month field
  352.      */
  353.      if (   i == 3
  354.          || (   (i == 2)
  355.              && (!isdigit(str8[1]))))
  356.       {
  357.         if (on_error_exit)
  358.           my_error (122, filename, line, line_buffer, *m);
  359.         *y = -1;
  360.       }
  361.    /*
  362.       Check if @... date variable statement or *... statement is given
  363.    */
  364.    if (i)
  365.     {
  366.       *len += i;
  367.       if (*str8 == RC_HDY_CHAR)
  368.        {
  369.          is_hdy_mode = TRUE;
  370.          if (i == 2)
  371.            *hc = (char)tolower(str8[1]);
  372.        }
  373.       else
  374.         if (*str8 == RC_NWD_CHAR)
  375.          {
  376.            is_hdy_mode = TRUE;
  377.            if (   (i == 2)
  378.                && (   toupper(str8[1]) == 'D'
  379.                    || toupper(str8[1]) == 'W'))
  380.              *hc = (char)toupper(str8[1]);
  381.            else
  382.             {
  383.               if (i == 2)
  384.                 /*
  385.                    Error, invalid mode specifying character given
  386.                 */
  387.                 *hc = (char)toupper(str8[1]);
  388.               else
  389.                 /*
  390.                    Error, no mode specifying character given
  391.                 */
  392.                 *hc = *str8;
  393.             }
  394.          }
  395.     }
  396.    /*
  397.       If special value 99 for month `m' is given,
  398.         set month to 12 (december)
  399.    */
  400.    if (*m == 99)
  401.      *m = MONTH_MAX;
  402.    /*
  403.       Error, invalid month field
  404.    */
  405.    if (   !is_hdy_mode
  406.        && (   *m > MONTH_MAX
  407.            || (   !*m
  408.                && (   (   (i == 1)
  409.                        && !isdigit(*str8))
  410.                    || (   (i == 2)
  411.                        && (   !isdigit(*str8)
  412.                            || !isdigit(str8[1])))
  413.                    || (   (i == 3)
  414.                        && (   !isdigit(*str8)
  415.                            || !isdigit(str8[1])
  416.                            || !isdigit(str8[2])))))))
  417.     {
  418.       if (on_error_exit)
  419.         my_error (122, filename, line, line_buffer, *m);
  420.       *y = -1;
  421.     }
  422.    /*
  423.       Get day (maximum 3 characters in this case, template is either `dd', `ww'  or `www')
  424.         resp., @... date variable or *... statement (maximum 7 characters in this case,
  425.         template is: -nnn`www')
  426.    */
  427.    i = 0;
  428.    while (   *ptr_char
  429.           && !MY_ISSPACE(*ptr_char)
  430.           && (i < ((is_hdy_mode) ? 7 : 3)))
  431.      str8[i++] = *ptr_char++;
  432.    str8[i] = '\0';
  433.    *d = atoi (str8);
  434.    if (i)
  435.      *len += i;
  436.    *is_weekday_mode = FALSE;
  437.    ptr_char--;
  438.    if (   isupper(*ptr_char)
  439.        || islower(*ptr_char)
  440.        || (   (i < 3)
  441.            && !is_hdy_mode))
  442.      ptr_char++;
  443.    if (!is_hdy_mode)
  444.     {
  445.       /*
  446.          Check for textual day name (either two or three characters),
  447.            template `ww' or `www'
  448.       */
  449.       if (!*d)
  450.        {
  451.          *d = compare_d_m_name (str8, DAy);
  452.          if (*d)
  453.           {
  454.             *is_weekday_mode = TRUE;
  455.             if (isdigit(str8[i-1]))
  456.               (*len)--;
  457.           }
  458.          if (!*d)
  459.           {
  460.             i = 0;
  461.             while (isdigit(str8[i]))
  462.               i++;
  463.             /*
  464.                Error, invalid day field
  465.             */
  466.             if (str8[i])
  467.              {
  468.                if (on_error_exit)
  469.                  my_error (121, filename, line, line_buffer, *d);
  470.                *y = -1;
  471.              }
  472.           }
  473.        }
  474.       else
  475.         /*
  476.            Error, invalid day field
  477.         */
  478.         if (   (i > 1)
  479.             && !isdigit(str8[1]))
  480.          {
  481.            if (on_error_exit)
  482.              my_error (121, filename, line, line_buffer, *d);
  483.            *y = -1;
  484.          }
  485.       /*
  486.          Check whether "n'th weekday of month" field exists
  487.       */
  488.       if (*ptr_char)
  489.         if (!MY_ISSPACE(*ptr_char))
  490.          {
  491.            if (isdigit(*ptr_char))
  492.             {
  493.               *n = (*ptr_char - '0');
  494.               if (*n)
  495.                {
  496.                  /*
  497.                     Error, invalid "n'th weekday of month" field
  498.                  */
  499.                  if (   (*n > 5)
  500.                      && (*n < 9))
  501.                   {
  502.                     if (on_error_exit)
  503.                       my_error (117, filename, line, line_buffer, *n);
  504.                     *y = -1;
  505.                   }
  506.                }
  507.             }
  508.            else
  509.              /*
  510.                 Error, missing separator between date part and `text'
  511.              */
  512.              if (on_error_exit)
  513.                my_error (116, filename, line, line_buffer, 0);
  514.            if (*ptr_char)
  515.              ptr_char++;
  516.            /*
  517.               Error, missing separator between date part and `text'
  518.            */
  519.            if (*ptr_char)
  520.              if (   !MY_ISSPACE(*ptr_char)
  521.                  && on_error_exit)
  522.                my_error (116, filename, line, line_buffer, 0);
  523.            /*
  524.               Error, "n'th weekday of month" entry set but invalid day encoded
  525.            */
  526.            if (   *n
  527.                && (   *d < DAY_MIN
  528.                    || *d > DAY_MAX))
  529.             {
  530.               if (on_error_exit)
  531.                 my_error (121, filename, line, line_buffer, *d);
  532.               *y = -1;
  533.             }
  534.            (*len)++;
  535.          }
  536.     }
  537.    else
  538.     {
  539.       auto char  *ptr2_char;
  540.  
  541.  
  542.       if (isdigit(*ptr_char))
  543.         ptr_char++;
  544.       /*
  545.          Error, missing separator between date part and `text'
  546.       */
  547.       if (*ptr_char)
  548.         if (   !MY_ISSPACE(*ptr_char)
  549.             && on_error_exit)
  550.           my_error (116, filename, line, line_buffer, 0);
  551.       /*
  552.          Compute standard date of '@' date variable date part of line
  553.            or '*' n'th weekday of year/weekday `ww[w]' of n'th week
  554.            in case an explicit year `yyyy' is given in date part
  555.       */
  556.       i = atoi(str8);
  557.       ptr2_char = str8;
  558.       if (   *ptr2_char == *ASC_LIT
  559.           || *ptr2_char == *DES_LIT)
  560.         ptr2_char++;
  561.       while (isdigit(*ptr2_char))
  562.         ptr2_char++;
  563.       if (*ptr2_char)
  564.        {
  565.          *hwd = compare_d_m_name (ptr2_char, DAy);
  566.          /*
  567.             Error, invalid textual short day name given
  568.          */
  569.          if (!*hwd)
  570.           {
  571.             if (on_error_exit)
  572.               my_error (123, filename, line, line_buffer, 0);
  573.             *hc = '\0';
  574.             *d = 0;
  575.             *y = -1;
  576.           }
  577.        }
  578.       if (*y >= 0)
  579.        {
  580.          if (*hc == RC_EASTER_CHAR)
  581.           {
  582.             if (!precomp_date (i, *hwd, d, m, *y, EAster))
  583.              {
  584.                if (!*y)
  585.                 {
  586.                   /*
  587.                      No explicit year `yyyy' given in date part of line
  588.                   */
  589.                   *hn = i;
  590.                   *d = 0;
  591.                   *m = 0;
  592.                 }
  593.                else
  594.                 {
  595.                   /*
  596.                      Invalid relative date given
  597.                   */
  598.                   *hc = '\0';
  599.                   *d = 0;
  600.                   *y = -1;
  601.                 }
  602.              }
  603.             else
  604.               *hc = '\0';
  605.           }
  606.          else
  607.            if (islower(*hc))
  608.             {
  609.               /*
  610.                  Try to assign local date variable if there is any set
  611.                    else try to assign global date variable if there is any set,
  612.                    otherwise we have to skip
  613.               */
  614.               if (   rc_dvar[IDX(*hc)].l.month
  615.                   || rc_dvar[IDX(*hc)].g.month)
  616.                {
  617.                  if (rc_dvar[IDX(*hc)].l.month)
  618.                   {
  619.                     *m = (int)rc_dvar[IDX(*hc)].l.month;
  620.                     *d = (int)rc_dvar[IDX(*hc)].l.day;
  621.                   }
  622.                  else
  623.                   {
  624.                     *m = (int)rc_dvar[IDX(*hc)].g.month;
  625.                     *d = (int)rc_dvar[IDX(*hc)].g.day;
  626.                   }
  627.                  if (!precomp_date (i, *hwd, d, m, *y, DVar))
  628.                   {
  629.                     if (!*y)
  630.                       /*
  631.                          No explicit year `yyyy' given in date part of line
  632.                       */
  633.                       *hn = i;
  634.                     else
  635.                      {
  636.                        /*
  637.                           Invalid relative date given
  638.                        */
  639.                        *hc = '\0';
  640.                        *d = 0;
  641.                        *y = -1;
  642.                      }
  643.                   }
  644.                  else
  645.                    *hc = '\0';
  646.                }
  647.               else
  648.                {
  649.                  /*
  650.                     Error, no such date variable defined
  651.                  */
  652.                  if (   (warning_level >= 0)
  653.                      && on_error_exit)
  654.                    dvar_warning (113, *hc, filename, line, line_buffer);
  655.                  *hc = '\0';
  656.                  *d = 0;
  657.                  *y = -1;
  658.                }
  659.             }
  660.            else
  661.              if (   *hc == 'D'
  662.                  || *hc == 'W')
  663.               {
  664.                 /*
  665.                    Try to compute the '*' n'th weekday of year resp.,
  666.                      weekday `ww[w]' of n'th week statement
  667.                 */
  668.                 if (*y == 0)
  669.                  {
  670.                    /*
  671.                       No explicit year `yyyy' given in date part of line
  672.                    */
  673.                    *hn = i;
  674.                    *d = 0;
  675.                    *m = 0;
  676.                  }
  677.                 else
  678.                   if (precomp_nth_wd (i, *hwd, hn, d, m, y,
  679.                                       ((*hc == 'D') ? DAy : WEek)))
  680.                     *hc = '\0';
  681.               }
  682.              else
  683.                /*
  684.                   Error, either invalid date variable character trails holiday
  685.                     mode character '@', or an invalid character trails the n'th
  686.                     weekday of year resp., weekday `ww[w]' of n'th week mode character '*'
  687.                */
  688.                if (on_error_exit)
  689.                  my_error (123, filename, line, line_buffer, 0);
  690.        }
  691.       if (*ptr_char)
  692.         ptr_char++;
  693.     }
  694.  
  695.    return(ptr_char);
  696. }
  697.  
  698.  
  699.  
  700. #  ifdef ANSI_PROTO
  701. PUBLIC Bool
  702. precomp_nth_wd (      int         diff,
  703.                 const int         wd,
  704.                       int        *n,
  705.                       int        *day,
  706.                       int        *month,
  707.                       int        *year,
  708.                 const Cmode_enum  mode)
  709. #  else /* !ANSI_PROTO */
  710. PUBLIC Bool
  711. precomp_nth_wd (diff, wd, n, day, month, year, mode)
  712.          int         diff;
  713.    const int         wd;
  714.          int        *n;
  715.          int        *day;
  716.          int        *month;
  717.          int        *year;
  718.    const Cmode_enum  mode;
  719. #  endif /* !ANSI_PROTO */
  720. /*
  721.    Precompute the date of n'th absolute weekday `wd' in year or
  722.      the date on weekday `wd' of n'th absolute week in year and
  723.      return TRUE in case date exits in year, otherwise FALSE
  724. */
  725. {
  726.    register int  j=0;
  727.    auto     int  i=0;
  728.  
  729.  
  730.    if (*year)
  731.     {
  732.       if (mode == DAy)
  733.        {
  734.          *day = DAY_MIN;
  735.          *month = MONTH_MIN;
  736.          if (wd)
  737.           {
  738.             if (   diff == WEEK_MAX+1
  739.                 || diff == 99)
  740.              {
  741.                i = diff;
  742.                diff = WEEK_MAX;
  743.              }
  744.           }
  745.          else
  746.           {
  747.             /*
  748.                If special value 999 for `diff' is given,
  749.                  set it to last day of year (365|366)
  750.             */
  751.             if (diff == 999)
  752.               diff = DAY_LAST + (days_of_february (*year) == 29);
  753.             i = diff--;
  754.           }
  755.        }
  756.       else
  757.        {
  758.          /*
  759.             `mode' == WEek
  760.          */
  761.          j = diff;
  762.          diff=i = weekno2jday (diff, *year);
  763.          if (diff > DAY_MIN)
  764.            diff--;
  765.          else
  766.            diff = 1;
  767.          if (jdate2sdate (diff, (days_of_february (*year)==29), day, month))
  768.            diff = 1;
  769.        }
  770.     }
  771.    if (!precomp_date (diff, wd, day, month, *year, DVar))
  772.     {
  773.       if (!*year)
  774.        {
  775.          /*
  776.             No explicit year `yyyy' given in date part of line
  777.          */
  778.          *day = 0;
  779.          *month = 0;
  780.          *n = diff;
  781.        }
  782.       else
  783.        {
  784.          /*
  785.             Invalid relative date given
  786.          */
  787.          *day = 0;
  788.          *month = 0;
  789.          *year = -1;
  790.        }
  791.       return(FALSE);
  792.     }
  793.    else
  794.     {
  795.       if (   wd
  796.           && (mode == DAy))
  797.        {
  798.          register int  year_old=*year;
  799.  
  800.  
  801.          if (i)
  802.            for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
  803.              next_date (day, month, year);
  804.          if (   (   (*day <= DAY_MAX)
  805.                  && (*year != year_old))
  806.              || weekday_of_date (DAY_MIN, MONTH_MIN, *year) == wd)
  807.            for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
  808.              prev_date (day, month, year);
  809.          if (i == WEEK_MAX+1)
  810.           {
  811.             i = DAY_MIN;
  812.             *month = MONTH_MIN;
  813.             (void)precomp_date (WEEK_MAX, wd, &i, month, *year, DVar);
  814.             if (   (*day == i)
  815.                 && (weekday_of_date (DAY_MIN, MONTH_MIN, *year) != wd))
  816.              {
  817.                /*
  818.                   Error, no such 53'rd weekday `ww[w]' of year
  819.                */
  820.                *day = 0;
  821.                *month = 0;
  822.                *year = -1;
  823.                return(FALSE);
  824.              }
  825.           }
  826.        }
  827.       else
  828.         /*
  829.            `mode' == WEek
  830.         */
  831.         if (   !wd
  832.             || i < DAY_MIN
  833.             || (   (j <= 1)
  834.                 && (*day == DAY_MAX+1)
  835.                 && (wd == DAY_MIN)))
  836.          {
  837.            if (*day >= DAY_MAX+i)
  838.              *day -= DAY_MAX;
  839.            else
  840.              if (   !wd
  841.                  && (   i < DAY_MIN
  842.                      || (   (*day == DAY_MIN+1)
  843.                          && (i == DAY_MIN))))
  844.                (*day)--;
  845.            if (*day < DAY_MIN)
  846.             {
  847.               /*
  848.                  Error, n'th week doesn't contain such a weekday `ww[w]'
  849.               */
  850.               *day = 0;
  851.               *month = 0;
  852.               *year = -1;
  853.               return(FALSE);
  854.             }
  855.          }
  856.     }
  857.  
  858.    return(TRUE);
  859. }
  860.  
  861.  
  862.  
  863. #  ifdef ANSI_PROTO
  864. PUBLIC Bool
  865. precomp_date (      int         diff,
  866.               const int         wd,
  867.                     int        *day,
  868.                     int        *month,
  869.               const int         year,
  870.               const Cmode_enum  mode)
  871. #  else /* !ANSI_PROTO */
  872.    PUBLIC Bool
  873. precomp_date (diff, wd, day, month, year, mode)
  874.          int         diff;
  875.    const int         wd;
  876.          int        *day;
  877.          int        *month;
  878.    const int         year;
  879.    const Cmode_enum  mode
  880. #  endif /* !ANSI_PROTO */
  881. /*
  882.    Precompute the date relative to Easter Sunday's date(mode==EAster) or
  883.      relative to date variables date(mode==DVar) plus displacement `diff'
  884.      or displacement `diff' `wd' and return TRUE in case date exits in year,
  885.      otherwise FALSE
  886. */
  887. {
  888.    register int  i;
  889.  
  890.  
  891.    if (   (   (mode == EAster)
  892.            && (year >= EASTER_MIN)
  893.            && (year <= EASTER_MAX))
  894.        || (   (mode == DVar)
  895.            && (year >= YEAR_MIN)
  896.            && (year <= YEAR_MAX)))
  897.     {
  898.       if (mode == EAster)
  899.         i = knuth_easter_formula (year);
  900.       else
  901.         i = day_of_year (*day, *month, year);
  902.       if (wd)
  903.        {
  904.          /*
  905.             Calculate date like:  3'rd(`diff') Friday(`wd') before Easter Sunday's date
  906.          */
  907.          if (   wd < DAY_MIN
  908.              || wd > DAY_MAX)
  909.            /*
  910.               Error, invalid weekday specified
  911.            */
  912.            return(FALSE);
  913.          else
  914.            if (!diff)
  915.              /*
  916.                 Error, a weekday but no difference specified
  917.              */
  918.              return(FALSE);
  919.            else
  920.             {
  921.               register int  act_wd;
  922.               auto     int  d;
  923.               auto     int  m;
  924.               auto     int  y=year;
  925.  
  926.  
  927.               jdate2sdate (i, (days_of_february (y)==29), &d, &m);
  928.               act_wd = weekday_of_date (d, m, y);
  929.               if (act_wd != wd)
  930.                {
  931.                  if (diff < 0)
  932.                   {
  933.                     /*
  934.                        Try to detect first weekday `wd' before actual date
  935.                     */
  936.                     while (act_wd != wd)
  937.                      {
  938.                        prev_date (&d, &m, &y);
  939.                        act_wd = weekday_of_date (d, m, y);
  940.                        i--;
  941.                      }
  942.                     diff++;
  943.                   }
  944.                  else
  945.                   {
  946.                     /*
  947.                        Try to detect first weekday `wd' after actual date
  948.                     */
  949.                     while (act_wd != wd)
  950.                      {
  951.                        next_date (&d, &m, &y);
  952.                        act_wd = weekday_of_date (d, m, y);
  953.                        i++;
  954.                      }
  955.                     diff--;
  956.                   }
  957.                }
  958.               if (y != year)
  959.                 /*
  960.                    Error, we have left year bounds
  961.                 */
  962.                 return(FALSE);
  963.               /*
  964.                  Calculate the difference
  965.               */
  966.               i += (diff * DAY_MAX);
  967.             }
  968.        }
  969.       else
  970.         /*
  971.            Calculate the difference
  972.         */
  973.         i += diff;
  974.       if (jdate2sdate (i, (days_of_february (year)==29), day, month))
  975.         return(TRUE);
  976.     }
  977.  
  978.    return(FALSE);
  979. }
  980.  
  981.  
  982.  
  983. #  ifdef ANSI_PROTO
  984. EXPORT Bool
  985. set_dvar (const char      *line_buffer,
  986.           const char      *filename,
  987.           const int        line,
  988.           const Dvar_enum  mode)
  989. #  else /* !ANSI_PROTO */
  990.    EXPORT Bool
  991. set_dvar (line_buffer, filename, line, mode)
  992.    const char      *line_buffer;
  993.    const char      *filename;
  994.    const int        line;
  995.    const Dvar_enum  mode;
  996. #  endif /* !ANSI_PROTO */
  997. /*
  998.    Scans given string `line_buffer' and tries to detect valid date variable
  999.      references, which can be:
  1000.        1) `dvar'=`mmdd'         --> assignment of a constant date expression `mmdd'
  1001.        2) `dvar'=`mmww[w]'<n>   --> assignment of a dynamic date expression
  1002.                                       n'th weekday `ww[w]' in month `mm'
  1003.        3) `dvar'=*d<n>[`ww[w]'] --> assignment of a dynamic date expression
  1004.                                       n'th weekday `ww[w]' of year
  1005.        4) `dvar'=*w<n>[`ww[w]'] --> assignment of a dynamic date expression
  1006.                                       weekday `ww[w]' of n'th week of year
  1007.        5) `dvar'=`dvar'         --> assignment of a date variable `dvar',
  1008.                                       which must be already defined
  1009.        6) `dvar'++              --> simple incrementation
  1010.        7) `dvar'--              --> simple decrementation
  1011.        8) `dvar'+=<n>           --> addition of a constant numeric factor <n>
  1012.        9) `dvar'-=<n>           --> subtraction of a constant numeric factor <n>
  1013.      a date variable name is valid from a...d and f...z (total 25 variables)
  1014.      because the `e' variable is always reserved for current Easter
  1015.      Sunday's date so we must skip any reference to this variable.
  1016.      no whitespace characters may occur between date variable, operator
  1017.      and value. Stores assignment (1)...(5) at position `date variable'
  1018.      into global date variable vector `rc_dvar[]' (either the local or the
  1019.      global ones, depending on given `mode', which can be either "GLobal"
  1020.      or "LOcal". assignments (2)...(4) may be used ONLY in local date variables).
  1021.      returns FALSE if an error occurs, otherwise TRUE.
  1022. */
  1023. {
  1024.    auto       int   i;
  1025.    auto       int   n;
  1026.    auto       int   m;
  1027.    auto       int   d;
  1028.    auto       char  op;
  1029.    auto       char  op2;
  1030.    auto const char *ptr_char=line_buffer;
  1031.    auto       Bool  is_error=FALSE;
  1032.    auto       Bool  skip_dvar_assign=FALSE;
  1033.  
  1034.  
  1035.    /*
  1036.       Skip and return error if invalid date variable name is given
  1037.    */
  1038.    if (   (   isupper(*line_buffer)
  1039.            || islower(*line_buffer))
  1040.        && (tolower(*line_buffer) != RC_EASTER_CHAR))
  1041.     {
  1042.       ptr_char++;
  1043.       /*
  1044.          Check if assignment (1)...(5) is given
  1045.       */
  1046.       if (*ptr_char != *RC_DVAR_ASSIGN)
  1047.        {
  1048.          if (   (*ptr_char != *RC_DVAR_ADD)
  1049.              && (*ptr_char != *RC_DVAR_SUB))
  1050.            /*
  1051.               Error, invalid first operator character found (no '+' or '-' given)
  1052.            */
  1053.            is_error = TRUE;
  1054.          else
  1055.           {
  1056.             /*
  1057.                Check if operation (6)...(9) is given
  1058.             */
  1059.             op = *ptr_char++;
  1060.             if (*ptr_char)
  1061.              {
  1062.                op2 = *ptr_char++;
  1063.                if (   op2 == op
  1064.                    || op2 == *RC_DVAR_ASSIGN)
  1065.                 {
  1066.                   if (mode == GLobal)
  1067.                    {
  1068.                      m = (int)rc_dvar[IDX(*line_buffer)].g.month;
  1069.                      d = (int)rc_dvar[IDX(*line_buffer)].g.day;
  1070.                    }
  1071.                   else
  1072.                    {
  1073.                      m = (int)rc_dvar[IDX(*line_buffer)].l.month;
  1074.                      d = (int)rc_dvar[IDX(*line_buffer)].l.day;
  1075.                    }
  1076.                   if (m)
  1077.                    {
  1078.                      if (   (   (op2 == *RC_DVAR_ADD)
  1079.                              && (m == MONTH_MAX)
  1080.                              && (d == dvec[MONTH_MAX-1]))
  1081.                          || (   (op2 == *RC_DVAR_SUB)
  1082.                              && (m == MONTH_MIN)
  1083.                              && (d == DAY_MIN)))
  1084.                       {
  1085.                         /*
  1086.                            Ignore line because year bounds are left
  1087.                         */
  1088.                         skip_dvar_assign = TRUE;
  1089.                         if (warning_level >= 0)
  1090.                           dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1091.                       }
  1092.                      else
  1093.                       {
  1094.                         /*
  1095.                            Compute day number of date in year
  1096.                         */
  1097.                         i = mvec[m-1] + d;
  1098.                         if (m > 2)
  1099.                           i += is_leap_year;
  1100.                         /*
  1101.                            Either ++ or -- found
  1102.                         */
  1103.                         if (op == op2)
  1104.                          {
  1105.                            if (op == *RC_DVAR_ADD)
  1106.                              /*
  1107.                                 Increment date of date variable by 1
  1108.                              */
  1109.                              i++;
  1110.                            else
  1111.                              /*
  1112.                                 Decrement date of date variable by 1
  1113.                              */
  1114.                              i--;
  1115.                          }
  1116.                         else
  1117.                          {
  1118.                            auto char  str4[4];
  1119.  
  1120.  
  1121.                            /*
  1122.                               Either '+=' or '-=' found,
  1123.                                 scan factor part (3 digits maximum, 0...365|366
  1124.                            */
  1125.                            d = 0;
  1126.                            while (   isdigit(*ptr_char)
  1127.                                   && (d < 3))
  1128.                              str4[d++] = *ptr_char++;
  1129.                            str4[d] = '\0';
  1130.                            d = atoi(str4);
  1131.                            if (d > DAY_LAST+is_leap_year)
  1132.                             {
  1133.                               /*
  1134.                                  Ignore line because an invalid displacement
  1135.                                    factor is defined which lefts year bounds
  1136.                               */
  1137.                               skip_dvar_assign = TRUE;
  1138.                               if (warning_level >= 0)
  1139.                                 dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1140.                             }
  1141.                            else
  1142.                             {
  1143.                               if (op == *RC_DVAR_ADD)
  1144.                                 /*
  1145.                                    Add factor to day number
  1146.                                 */
  1147.                                 i += d;
  1148.                               else
  1149.                                 /*
  1150.                                    Subtract day number by factor
  1151.                                 */
  1152.                                 i -= d;
  1153.                             }
  1154.                          }
  1155.                         /*
  1156.                            Calculate date in year
  1157.                         */
  1158.                         if (!skip_dvar_assign)
  1159.                          {
  1160.                            if (   i < DAY_MIN
  1161.                                || i > DAY_LAST+is_leap_year)
  1162.                             {
  1163.                               /*
  1164.                                  Ignore line because year bounds are left
  1165.                               */
  1166.                               skip_dvar_assign = TRUE;
  1167.                               if (warning_level >= 0)
  1168.                                 dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1169.                             }
  1170.                            else
  1171.                              /*
  1172.                                 Calculate month and day
  1173.                              */
  1174.                              (void)jdate2sdate (i, is_leap_year, &d, &m);
  1175.                          }
  1176.                       }
  1177.                    }
  1178.                   else
  1179.                    {
  1180.                      /*
  1181.                         Error, date variable undefined
  1182.                      */
  1183.                      skip_dvar_assign = TRUE;
  1184.                      if (warning_level >= 0)
  1185.                        dvar_warning (113, *line_buffer, filename, line, line_buffer);
  1186.                    }
  1187.                 }
  1188.                else
  1189.                  /*
  1190.                     Error, invalid second operator character found
  1191.                       (no '=', '+' or '-' given resp., illegal combination of '+' and '-')
  1192.                  */
  1193.                  is_error = TRUE;
  1194.              }
  1195.             else
  1196.               /*
  1197.                  Error, incomplete operator found (no +=, -=, ++ or -- given)
  1198.               */
  1199.               is_error = TRUE;
  1200.           }
  1201.        }
  1202.       else
  1203.        {
  1204.          /*
  1205.             Assignment (1)...(5) to date variable found (simple '=' given),
  1206.               scan expression part of date variable definition. assignments
  1207.               (2)...(4) are ONLY allowed for local date variables.
  1208.          */
  1209.          i = 0;
  1210.          ptr_char++;
  1211.          if (!*ptr_char)
  1212.            /*
  1213.               Error, no argument after '=' character given
  1214.            */
  1215.            is_error = TRUE;
  1216.          else
  1217.           {
  1218.             if (   (   isupper(*ptr_char)
  1219.                     || islower(*ptr_char))
  1220.                 && !isupper(*(ptr_char+1))
  1221.                 && !islower(*(ptr_char+1)))
  1222.              {
  1223.                op = *ptr_char;
  1224.                ptr_char++;
  1225.                if (   !*ptr_char
  1226.                    || MY_ISSPACE(*ptr_char))
  1227.                 {
  1228.                   if (tolower(op) == RC_EASTER_CHAR)
  1229.                    {
  1230.                      /*
  1231.                         Error, date variable invalid
  1232.                      */
  1233.                      skip_dvar_assign = TRUE;
  1234.                      if (warning_level >= 0)
  1235.                        dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1236.                    }
  1237.                   else
  1238.                    {
  1239.                      /*
  1240.                         If character after '=' is alphabetic and is not trailed
  1241.                           by digits, assume that assignment (5) given
  1242.                      */
  1243.                      if (mode == GLobal)
  1244.                       {
  1245.                         m = (int)rc_dvar[IDX(op)].g.month;
  1246.                         d = (int)rc_dvar[IDX(op)].g.day;
  1247.                       }
  1248.                      else
  1249.                       {
  1250.                         m = (int)rc_dvar[IDX(op)].l.month;
  1251.                         d = (int)rc_dvar[IDX(op)].l.day;
  1252.                       }
  1253.                    }
  1254.                 }
  1255.                else
  1256.                  /*
  1257.                     Error, invalid date variable name given
  1258.                  */
  1259.                  is_error = TRUE;
  1260.              }
  1261.             else
  1262.              {
  1263.                auto int   y=year;
  1264.                auto int   len;
  1265.                auto Bool  is_weekday_mode;
  1266.  
  1267.  
  1268.                sprintf(str, "%0*d%s", len_year_max, y, ptr_char);
  1269.                /*
  1270.                   rc_get_date() arguments `len' and `i' are dummys
  1271.                     only and must be given.  they are not respected!
  1272.                */
  1273.                (void)rc_get_date (str, &is_weekday_mode, &d, &m, &y, &n, &len,
  1274.                                   &op, &i, &i, filename, line, line_buffer, TRUE);
  1275.                if (y != -1)
  1276.                 {
  1277.                   /*
  1278.                      Check if assignments (3)...(4) are given
  1279.                   */
  1280.                   if (   (mode == GLobal)
  1281.                       && (   op
  1282.                           || is_weekday_mode))
  1283.                     is_error = TRUE;
  1284.                   else
  1285.                    {
  1286.                      /*
  1287.                         Assignments (1)..(2) are given
  1288.                      */
  1289.                      if (   m < MONTH_MIN
  1290.                          || m > MONTH_MAX)
  1291.                        /*
  1292.                           Error, invalid month given
  1293.                        */
  1294.                        is_error = TRUE;
  1295.                      else
  1296.                       {
  1297.                         i = dvec[m-1];
  1298.                         if (m == 2)
  1299.                           i += is_leap_year;
  1300.                         /*
  1301.                            Check for assignment (2) `dvar'=`mmww[w]'<n> (`ww'=mo...su,
  1302.                              `www'=mon..sun, n=1...5|9), e.g.:
  1303.                              x=03mo3  sets `x' to date of 3'rd Monday in March
  1304.                              x=03mon3  sets `x' to date of 3'rd Monday in March, too
  1305.                         */
  1306.                         if (is_weekday_mode)
  1307.                          {
  1308.                            if (n == 9)
  1309.                              d = eval_holiday (i, m, year, d, FALSE);
  1310.                            else
  1311.                             {
  1312.                               d = eval_holiday (DAY_MIN, m, year, d, TRUE);
  1313.                               d += (DAY_MAX * (n - 1));
  1314.                               if (d > i)
  1315.                                {
  1316.                                  /*
  1317.                                     Month contains no such "n'th weekday of month"
  1318.                                       ignore the assignment but produce NO error!!
  1319.                                  */
  1320.                                  skip_dvar_assign = TRUE;
  1321.                                  if (warning_level >= 0)
  1322.                                    dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1323.                                }
  1324.                             }
  1325.                          }
  1326.                         else
  1327.                          {
  1328.                            /*
  1329.                               Assume assignment (1) is given
  1330.                            */
  1331.                            if (d == 99)
  1332.                              d = i;
  1333.                            if (   d < DAY_MIN
  1334.                                || d > i)
  1335.                              /*
  1336.                                 Error, invalid day given
  1337.                              */
  1338.                              is_error = TRUE;
  1339.                          }
  1340.                       }
  1341.                    }
  1342.                 }
  1343.                else
  1344.                 {
  1345.                   /*
  1346.                      Year contains no such date,
  1347.                        ignore the assignment but produce NO error!!
  1348.                   */
  1349.                   skip_dvar_assign = TRUE;
  1350.                   if (warning_level >= 0)
  1351.                     dvar_warning (112, *line_buffer, filename, line, line_buffer);
  1352.                 }
  1353.              }
  1354.           }
  1355.        }
  1356.       if (   !is_error
  1357.           && !skip_dvar_assign)
  1358.        {
  1359.          /*
  1360.             Store the assigned/calculated date
  1361.          */
  1362.          if (mode == GLobal)
  1363.           {
  1364.             rc_dvar[IDX(*line_buffer)].g.month = (char)m;
  1365.             rc_dvar[IDX(*line_buffer)].g.day = (char)d;
  1366.           }
  1367.          else
  1368.           {
  1369.             rc_dvar[IDX(*line_buffer)].l.month = (char)m;
  1370.             rc_dvar[IDX(*line_buffer)].l.day = (char)d;
  1371.           }
  1372.        }
  1373.     }
  1374.    else
  1375.      /*
  1376.         Error, invalid date variable name given (not a...df...z)
  1377.      */
  1378.      is_error = TRUE;
  1379.  
  1380.    return((Bool)!is_error);
  1381. }
  1382.  
  1383.  
  1384.  
  1385. #  ifdef ANSI_PROTO
  1386. PUBLIC void
  1387. nth_weekday_of_month (      int  *d,
  1388.                             int  *m,
  1389.                             int  *y,
  1390.                       const int  *n,
  1391.                             Bool *is_weekday_mode)
  1392. #  else /* !ANSI_PROTO */
  1393.    PUBLIC void
  1394. nth_weekday_of_month (d, m, y, n, is_weekday_mode)
  1395.          int  *d;
  1396.          int  *m;
  1397.          int  *y;
  1398.    const int  *n;
  1399.          Bool *is_weekday_mode;
  1400. #  endif /* !ANSI_PROTO */
  1401. /*
  1402.    If "n'th weekday of month" field is encoded:
  1403.      compute the according date and return it in &d, &m, &y;
  1404.      if conversion error occurs, return &y==-1 (special value)
  1405. */
  1406. {
  1407.    register int   i;
  1408.    register int   j=0;
  1409.    auto     int   dd=0;
  1410.    auto     int   mm=0;
  1411.    auto     Bool  year_set=FALSE;
  1412.    auto     Bool  year_modified=FALSE;
  1413.  
  1414.  
  1415.    if (   *n
  1416.        && (   !rc_year_flag
  1417.            || (   *m
  1418.                && rc_year_flag))
  1419.        && (   !rc_period_list
  1420.            || (   *m
  1421.                && rc_period_list)))
  1422.     {
  1423.       if (   !*m
  1424.           && (   is_3month_mode
  1425.               || is_3month_mode2
  1426.               || fiscal_month > MONTH_MIN))
  1427.         ;   /* If fiscal year resp., 3 month mode and no month encoded, skip evaluation */
  1428.       else
  1429.        {
  1430.          *is_weekday_mode = FALSE;
  1431.          if (!*y)
  1432.           {
  1433.             year_set = TRUE;
  1434.             *y = year;
  1435.           }
  1436.          if (!*m)
  1437.           {
  1438.             *m = month;
  1439.             /*
  1440.                [-c][<n>]w or [-c]t option set:
  1441.                  lookahead whether week ends in month it started
  1442.             */
  1443.             if (   rc_week_flag
  1444.                 || rc_tomorrow_flag)
  1445.              {
  1446.                /*
  1447.                   <0000|`yyyy'>00`ww[w]'<n> event is in last week of last month of previous year
  1448.                */
  1449.                if (   (*n > 3)
  1450.                    && (day < DAY_MIN))
  1451.                 {
  1452.                   i = (days_of_february (year-1) == 29);
  1453.                   j = day + DAY_LAST + i;
  1454.                   (void)jdate2sdate (j, i, &dd, &mm);
  1455.                 }
  1456.                else
  1457.                  if (*n == 1)
  1458.                   {
  1459.                     /*
  1460.                        <0000|`yyyy'>00`ww[w]'<n> event is in first week of next month of actual year
  1461.                     */
  1462.                     if (   (day+DAY_MAX-1 > 0)
  1463.                         && (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
  1464.                       (void)jdate2sdate (day+DAY_MAX-1, is_leap_year, &dd, &mm);
  1465.                     else
  1466.                      {
  1467.                        /*
  1468.                           <0000|`yyyy'>00`ww[w]'<n> event is in first week first month of next year
  1469.                        */
  1470.                        i = (days_of_february (year+1) == 29);
  1471.                        j = (day + DAY_MAX - 1) - (DAY_LAST + is_leap_year);
  1472.                        (void)jdate2sdate (j, i, &dd, &mm);
  1473.                      }
  1474.                   }
  1475.                dd = *d;
  1476.              }
  1477.           }
  1478.          else
  1479.            if (   year_set
  1480.                && (   rc_week_flag
  1481.                    || rc_tomorrow_flag))
  1482.             {
  1483.               if (   (*n == 9)
  1484.                   && (*m == MONTH_MAX)
  1485.                   && (*y > YEAR_MIN)
  1486.                   && (day < DAY_MIN))
  1487.                {
  1488.                  year_modified = TRUE;
  1489.                  (*y)--;
  1490.                }
  1491.               else
  1492.                 if (   (*n == 1)
  1493.                     && (*m == MONTH_MIN)
  1494.                     && (*y < YEAR_MAX)
  1495.                     && (day+DAY_MAX >= DAY_LAST+is_leap_year))
  1496.                  {
  1497.                    year_modified = TRUE;
  1498.                    (*y)++;
  1499.                  }
  1500.             }
  1501.          if (   year_set
  1502.              && (*y < YEAR_MAX)
  1503.              && (   (fiscal_month > MONTH_MIN)
  1504.                  && (*m < fiscal_month)))
  1505.            if (!year_modified)
  1506.              (*y)++;
  1507.          if (*m == 2)
  1508.            i = days_of_february (*y);
  1509.          else
  1510.            i = dvec[*m-1];
  1511.          if (*n == 9)
  1512.            *d = eval_holiday (i, *m, *y, *d, FALSE);
  1513.          else
  1514.           {
  1515.             *d = eval_holiday (DAY_MIN, *m, *y, *d, TRUE);
  1516.             *d += (DAY_MAX * (*n - 1));
  1517.             /*
  1518.                The "n'th weekday of month" doesn't occur in month:
  1519.                  skip it
  1520.             */
  1521.             if (*d > i)
  1522.               *y = -1;
  1523.           }
  1524.          /*
  1525.             [-c][<n>]w or [-c]t option set:
  1526.               correction for lookahead
  1527.          */
  1528.          if (   mm
  1529.              && (   rc_week_flag
  1530.                  || rc_tomorrow_flag))
  1531.           {
  1532.             if (   (*n == 1)
  1533.                 && (mm != *m))
  1534.              {
  1535.                *m = mm;
  1536.                if (   (day+DAY_MAX-1 > 0)
  1537.                    && (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
  1538.                  ;   /* Void, don't change year of event */
  1539.                else
  1540.                  if (   year_set
  1541.                      && (year < YEAR_MAX))
  1542.                    *y = year + 1;
  1543.                *d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
  1544.              }
  1545.             else
  1546.               if (   (*n > 3)
  1547.                   && (   (   adate_set
  1548.                           && (mm == *m))
  1549.                       || (   !adate_set
  1550.                           && (mm != *m))))
  1551.                {
  1552.                  if (!adate_set)
  1553.                    *m = mm;
  1554.                  if (   year_set
  1555.                      && (year > YEAR_MIN))
  1556.                    *y = year - 1;
  1557.                  if (*n == 9)
  1558.                    *d = eval_holiday (dvec[MONTH_MAX-1], *m, *y, dd, FALSE);
  1559.                  else
  1560.                   {
  1561.                     *d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
  1562.                     *d += (DAY_MAX * (*n - 1));
  1563.                     /*
  1564.                        The "n'th weekday of month" doesn't occur in month:
  1565.                          skip it
  1566.                     */
  1567.                     if (*d > dvec[MONTH_MAX-1])
  1568.                       *y = -1;
  1569.                   }
  1570.                }
  1571.           }
  1572.        }
  1573.     }
  1574. }
  1575.  
  1576.  
  1577.  
  1578. #  ifdef ANSI_PROTO
  1579. PUBLIC void
  1580. prev_date (int *day,
  1581.            int *month,
  1582.            int *year)
  1583. #  else /* !ANSI_PROTO */
  1584.    PUBLIC void
  1585. prev_date (day, month, year)
  1586.    int *day;
  1587.    int *month;
  1588.    int *year;
  1589. #  endif /* !ANSI_PROTO */
  1590. /*
  1591.    Sets delivered date back by one day (to yesterdays date)
  1592. */
  1593. {
  1594.    (*day)--;
  1595.    if (   !*day
  1596.        || !valid_date (*day, *month, *year))
  1597.     {
  1598.       (*month)--;
  1599.       if (*month < MONTH_MIN)
  1600.        {
  1601.          *month = MONTH_MAX;
  1602.          (*year)--;
  1603.        }
  1604.       if (*month == 2)
  1605.         *day = days_of_february (*year);
  1606.       else
  1607.         *day = dvec[*month-1];
  1608.     }
  1609. }
  1610.  
  1611.  
  1612.  
  1613. #  ifdef ANSI_PROTO
  1614. PUBLIC void
  1615. next_date (int *day,
  1616.            int *month,
  1617.            int *year)
  1618. #  else /* !ANSI_PROTO */
  1619.    PUBLIC void
  1620. next_date (day, month, year)
  1621.    int *day;
  1622.    int *month;
  1623.    int *year;
  1624. #  endif /* !ANSI_PROTO */
  1625. /*
  1626.    Sets delivered date forwards by one day (to tomorrows date)
  1627. */
  1628. {
  1629.    (*day)++;
  1630.    if (!valid_date (*day, *month, *year))
  1631.     {
  1632.       *day = DAY_MIN;
  1633.       if (*month == MONTH_MAX)
  1634.        {
  1635.          *month = MONTH_MIN;
  1636.          (*year)++;
  1637.        }
  1638.       else
  1639.         (*month)++;
  1640.     }
  1641. }
  1642.  
  1643.  
  1644.  
  1645. #  ifdef ANSI_PROTO
  1646. PUBLIC void
  1647. num2date (Ulint  julian_days,
  1648.           int   *day,
  1649.           int   *month,
  1650.           int   *year)
  1651. #  else /* !ANSI_PROTO */
  1652.    PUBLIC void
  1653. num2date (julian_days, day, month, year)
  1654.    Ulint  julian_days;
  1655.    int   *day;
  1656.    int   *month;
  1657.    int   *year;
  1658. #  endif /* !ANSI_PROTO */
  1659. /*
  1660.    Converts a delivered absolute number of days `julian_days' to a standard date
  1661.      (since 00010101(==`yyyymmdd'), returned in &day, &month and &year)
  1662.      respecting the missing period of the Gregorian reformation
  1663. */
  1664. {
  1665.    auto     double  x;
  1666.    auto     Ulint   jdays=date2num (GREG_F_DAY-1, GREG_MONTH, GREG_YEAR);
  1667.    register int     i;
  1668.  
  1669.  
  1670.    if (julian_days > jdays)
  1671.      julian_days += (Ulint)(GREG_L_DAY - GREG_F_DAY + 1);
  1672.    x = (double)julian_days / (DAY_LAST + 0.25);
  1673.    i = (int)x;
  1674.    if ((double)i != x)
  1675.      *year = i + 1;
  1676.    else
  1677.     {
  1678.       *year = i;
  1679.       i--;
  1680.     }
  1681.    if (julian_days > jdays)
  1682.     {
  1683.       /*
  1684.          Correction for Gregorian years
  1685.       */
  1686.       julian_days -= (Ulint)((*year / 400) - (GREG_YEAR / 400));
  1687.       julian_days += (Ulint)((*year / 100) - (GREG_YEAR / 100));
  1688.       x = (double)julian_days / (DAY_LAST + 0.25);
  1689.       i = (int)x;
  1690.       if ((double)i != x)
  1691.         *year = i + 1;
  1692.       else
  1693.        {
  1694.          *year = i;
  1695.          i--;
  1696.        }
  1697.       if (   (*year % 400)
  1698.           && !(*year % 100))
  1699.         julian_days--;
  1700.     }
  1701.    i = (int)(julian_days - (Ulint)(i * (DAY_LAST + 0.25)));
  1702.    /*
  1703.       Correction for Gregorian centuries
  1704.    */
  1705.    if (   (*year > GREG_YEAR)
  1706.        && (*year % 400)
  1707.        && !(*year % 100)
  1708.        && (i < ((*year/100)-(GREG_YEAR/100))-((*year/400)-(GREG_YEAR/400))))
  1709.      i++;
  1710.    (void)jdate2sdate (i, (days_of_february (*year)==29), day, month);
  1711. }
  1712.  
  1713.  
  1714.  
  1715. #  ifdef ANSI_PROTO
  1716. PUBLIC Slint
  1717. d_between (const int d1,
  1718.            const int m1,
  1719.            const int y1,
  1720.            const int d2,
  1721.            const int m2,
  1722.            const int y2)
  1723. #  else /* !ANSI_PROTO */
  1724.    PUBLIC Slint
  1725. d_between (d1, m1, y1, d2, m2, y2)
  1726.    const int d1;
  1727.    const int m1;
  1728.    const int y1;
  1729.    const int d2;
  1730.    const int m2;
  1731.    const int y2;
  1732. #  endif /* !ANSI_PROTO */
  1733. /*
  1734.    Computes the amount of days between date1(base date) and date2
  1735.      exclusive date1 and date2, and adds 1 to result
  1736. */
  1737. {
  1738.    return(date2num (d2, m2, y2)-date2num (d1, m1, y1));
  1739. }
  1740.  
  1741.  
  1742.  
  1743. #  ifdef ANSI_PROTO
  1744. PUBLIC Slint
  1745. w_between (const int d1,
  1746.            const int m1,
  1747.            const int y1,
  1748.            const int d2,
  1749.            const int m2,
  1750.            const int y2)
  1751. #  else /* !ANSI_PROTO */
  1752.    PUBLIC Slint
  1753. w_between (d1, m1, y1, d2, m2, y2)
  1754.    const int d1;
  1755.    const int m1;
  1756.    const int y1;
  1757.    const int d2;
  1758.    const int m2;
  1759.    const int y2;
  1760. #  endif /* !ANSI_PROTO */
  1761. /*
  1762.    Computes the amount of weeks between date1(base date) and date2
  1763.      exclusive date1 and date2, and adds 1 to result
  1764. */
  1765. {
  1766.    auto     Ulint  date1=date2num (d1, m1, y1);
  1767.    auto     Ulint  date2=date2num (d2, m2, y2);
  1768.    auto     Slint  diff;
  1769.    auto     Slint  result;
  1770.  
  1771.  
  1772.    diff = (Slint)date2 - (date1 - (SYEAR(weekday_of_date (d1, m1, y1), start_day)) + 1);
  1773.    result = diff / DAY_MAX;
  1774.    if (   (diff % DAY_MAX)
  1775.        && (diff < 0L))
  1776.      result--;
  1777.  
  1778.    return(result);
  1779. }
  1780.  
  1781.  
  1782.  
  1783. #  ifdef ANSI_PROTO
  1784. PUBLIC Slint
  1785. m_between (const int m1,
  1786.            const int y1,
  1787.            const int m2,
  1788.            const int y2)
  1789. #  else /* !ANSI_PROTO */
  1790.    PUBLIC Slint
  1791. m_between (m1, y1, m2, y2)
  1792.    const int m1;
  1793.    const int y1;
  1794.    const int m2;
  1795.    const int y2;
  1796. #  endif /* !ANSI_PROTO */
  1797. /*
  1798.    Computes the amount of months between date1(base date) and date2
  1799.      exclusive date1 and date2, and adds 1 to result
  1800. */
  1801. {
  1802.    return(((y2 - y1) * MONTH_MAX) + (m2 - m1));
  1803. }
  1804.  
  1805.  
  1806.  
  1807. #  ifdef ANSI_PROTO
  1808. LOCAL void
  1809. dvar_warning (const int   exit_status,
  1810.               const char  dvar,
  1811.               const char *filename,
  1812.               const int   line,
  1813.               const char *text)
  1814. #  else /* !ANSI_PROTO */
  1815.    LOCAL void
  1816. dvar_warning (dvar, filename, line, text)
  1817.    const char  dvar;
  1818.    const char *filename;
  1819.    const int   line;
  1820.    const char *text;
  1821. #  endif /* !ANSI_PROTO */
  1822. /*
  1823.    Prints a warning message in case an operation on a date variable is invalid
  1824.      and terminates program if `warning_level' is set to max
  1825. */
  1826. {
  1827.    *str = '\0';
  1828.    print_text (stderr, str, INternal);
  1829.    switch (exit_status)
  1830.     {
  1831.       case 113:
  1832. #  if USE_GER
  1833.         sprintf(str, "Datumvariable `%c' undefiniert in Datei `%s'.", dvar, filename);
  1834. #  else /* !USE_GER */
  1835.         sprintf(str, "Date variable `%c' undefined in file `%s'.", dvar, filename);
  1836. #  endif /* !USE_GER */
  1837.         break;
  1838.       case 112:
  1839. #  if USE_GER
  1840.         sprintf(str, "Datumwert ung"UE"ltig (Variable `%c') in Datei `%s'.", dvar, filename);
  1841. #  else /* !USE_GER */
  1842.         sprintf(str, "Invalid date value (variable `%c') in file `%s'.", dvar, filename);
  1843. #  endif /* !USE_GER */
  1844.         break;
  1845.       default:
  1846.         /*
  1847.            This case MUST be an internal error!
  1848.         */
  1849.         abort();
  1850.     }
  1851.    print_text (stderr, str, INternal);
  1852. #  if USE_GER
  1853.    if (!line)
  1854.      sprintf(str, "Argument `%s' in Kommandozeile ignoriert", text);
  1855.    else
  1856.      sprintf(str, "Zeile %d ignoriert: %s", line, text);
  1857. #  else /* !USE_GER */
  1858.    if (!line)
  1859.      sprintf(str, "Argument `%s' of command line ignored", text);
  1860.    else
  1861.      sprintf(str, "Line %d ignored %s", line, text);
  1862. #  endif /* !USE_GER */
  1863.    print_text (stderr, str, INternal);
  1864.    if (warning_level >= WARN_LVL_MAX)
  1865.     {
  1866. #  if USE_GER
  1867.       strcpy(str, "Abbruch!");
  1868. #  else /* !USE_GER */
  1869.       strcpy(str, "Abort!");
  1870. #  endif /* !USE_GER */
  1871.       print_text (stderr, str, INternal);
  1872.       exit(exit_status);
  1873.     }
  1874. }
  1875. #endif /* USE_RC */
  1876.